using System.Reflection;
using System.Reflection.Metadata.Ecma335;
using Admin2025.Domain.Events;
using MediatR;

namespace Admin2025.Application.Events;

//基于反射的领域事件通知工厂
//自动发现并创建对应的通知类型，无需手动维护映射关系
public class ReflectionDomainEventNotificationFractory : IDomainEventNotificationFactory
{
    private static readonly Dictionary<Type, Type> _eventToNotificationMap = new();
    private static readonly object _lock = new();
    private static bool _initialized = false;
    //根据领域事件对应的MediatR通知
    public INotification? CreateNotification(IDomainEvent domainEvent)
    {
        EnsureInitialized();

        var eventType = domainEvent.GetType();
        if (_eventToNotificationMap.TryGetValue(eventType, out var notificationType))
        {
            try
            {
                //创建通知实例，假设构造函数接受领域事件作为参数
                return (INotification?)Activator.CreateInstance(notificationType, domainEvent);
            }
            catch (Exception)
            {
                //如果创建失败，返回null
                return null;
            }
        }
        return null;
    }

    //初始化事件到通知的映射关系
    private static void EnsureInitialized()
    {
        if (_initialized) return;

        lock (_lock)
        {
            if (_initialized) return;
            BuildEventToNotificationMap();
            _initialized = true;
        }
    }

    //构建事件到通知的映射关系
    //扫描当前程序集中所有实现了INotification的类，
    //查找其构造函数参数类型，如果参数类型实现了IDomainEvent,则建立映射关系
    private static void BuildEventToNotificationMap()
    {
        var currentAssembly = Assembly.GetExecutingAssembly();

        //找到所有实现INotification的类型
        var notificationTypes = currentAssembly.GetTypes().Where(t => t.IsClass && !t.IsAbstract && typeof(INotification).IsAssignableFrom(t)).ToArray();
        foreach (var notificationType in notificationTypes)
        {
            //查找构造函数，寻找接受IDomainEvent参数的构造函数
            var constructors = notificationType.GetConstructors();

            foreach (var constructor in constructors)
            {
                var parameters = constructor.GetParameters();
                // 如果构造函数只有一个参数，且该参数实现了IDomainEvent
                if (parameters.Length == 1)
                {
                    var parameterType = parameters[0].ParameterType;
                    if (typeof(IDomainEvent).IsAssignableFrom(parameterType))
                    {
                        _eventToNotificationMap[parameterType] = notificationType;
                    }
                }
            }
           

        }
    }
}